from socket import socket, SOCK_STREAM, AF_INET
from datetime import datetime
from threading import Thread
import json
import time
import traceback
from utils import process_logger, COMCODE, DateEncoder


class serversocket:
    def __init__(self, info_queue, op_queue, clients, lock_clients):
        # self.server.close()

        self.con_count = 0
        self.info_queue = info_queue
        self.op_queue = op_queue
        self.clients = clients
        self.lock_clients = lock_clients

    @process_logger
    def connect(self, ip, port):
        try:
            self.server = socket(family=AF_INET, type=SOCK_STREAM)
            self.server.bind((ip, port))
            self.server.listen(512)
            print("服务器启动开始监听...")
            while True:
                client, addr = self.server.accept()
                print(str(addr) + "连接到了服务器.")
                self.con_count += 1
                self.info_queue.put(
                    (
                        "lb_con_text",
                        "No. " + str(self.con_count) + " Connected.",
                    )
                )
                self.op_queue.put(("loadLocal", {}))
                Thread(
                    target=self.recvMsg, args=(client,), daemon=True
                ).start()

        except Exception as e:
            if e.args[0] == 10048:
                print("PORT IS USED")
            traceback.print_exc()

    @process_logger
    def lis_start(self, ip, port):
        if hasattr(self, "t_connect") and self.t_connect.is_alive():
            print("Already Listening")
            return
        self.t_connect = Thread(
            target=self.connect, args=(ip, port), daemon=True
        )
        self.t_connect.start()

    @process_logger
    def lis_stop(self):

        for client in self.clients.values():

            if client.fileno() != -1:
                try:
                    self.sendMsg(-1, 1, "EXIT", client)
                    self.clients.pop(client)
                except:
                    pass

        if hasattr(self, "server"):
            self.server.close()

    @process_logger
    def recvMsg(self, client):
        while True:
            try:
                msg_item = client.recv(1024).decode("utf8") + "\n"
                print("server", msg_item)
                msg_item = json.loads(msg_item)
                msg_item["time"] = datetime.strptime(
                    msg_item["time"], "%Y-%m-%d %H:%M:%S"
                )
                if msg_item["type"] == -1:
                    self.info_queue.put(
                        ("lb_con_text", "Client Exit")
                    )
                    break
                elif msg_item["type"] == 3:
                    self.recvFile(msg_item, client)
                elif msg_item["type"] == COMCODE["login"]:
                    self.op_queue.put(
                        (
                            "validate_usr",
                            {
                                "usr": msg_item["usr"],
                                "psd": msg_item["psd"],
                                "client": client,
                            },
                        )
                    )
                elif msg_item["type"] == COMCODE["register"]:
                    self.op_queue.put(
                        (
                            "register_usr",
                            {
                                "usr": msg_item["usr"],
                                "psd": msg_item["psd"],
                                "client": client,
                            },
                        )
                    )
                elif msg_item["type"] == COMCODE["add_friend"]:
                    self.op_queue.put(
                        (
                            "addFriend",
                            {
                                "usr_1": self.clients.inverse[client],
                                "usr_2": int(msg_item["msg"]),
                            },
                        )
                    )

                elif msg_item["type"] == COMCODE["del_friend"]:
                    self.op_queue.put(
                        (
                            "delFriend",
                            {
                                "usr_1": self.clients.inverse[client],
                                "usr_2": int(msg_item["msg"]),
                            },
                        )
                    )

                self.op_queue.put(
                    ("storeMsg", {"msg_item": msg_item})
                )
            except:
                traceback.print_exc()
                break
        client.close()
        self.con_count -= 1
        self.info_queue.put(
            ("lb_con_text", "No. Connected:" + str(self.con_count))
        )
        self.clients.pop(self.clients.inverse[client])
        print("exit clients", self.clients)
        self.info_queue.put("tx_dialog")

    @process_logger
    def recvFile(self, item, client):
        file_size, file_name = (
            item["msg"][0],
            item["msg"][1],
        )
        with open(file_name, "wb") as f:
            written_length = 0
            while written_length < file_size:
                if file_size - written_length >= 1024:
                    recv_chunk = client.recv(1024)
                else:
                    recv_chunk = client.recv(
                        file_size - written_length
                    )
                f.write(recv_chunk)
                written_length += len(recv_chunk)

    @process_logger
    def sendMsg(
        self,
        msg_item,
        client,
    ):

        client.send(
            bytes(
                json.dumps(msg_item, cls=DateEncoder),
                encoding="utf8",
            )
        )

        time.sleep(0.1)

        return msg_item

    def close_server(self):
        self.lis_stop()
        self.root.destroy()
